/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.system.service.impl;

import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.base.CharMatcher;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.constant.ConstantUtils;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.system.domain.*;
import me.zhengjie.modules.system.repository.CourseSigninRepository;
import me.zhengjie.modules.system.service.*;
import me.zhengjie.modules.system.service.dto.CourseSigninDto;
import me.zhengjie.modules.system.service.dto.CourseSigninQueryCriteria;
import me.zhengjie.modules.system.service.dto.ExamResultQueryDto;
import me.zhengjie.modules.system.service.dto.ExamResultQueryTestDto;
import me.zhengjie.modules.system.service.mapstruct.CourseSigninMapper;
import me.zhengjie.modules.web.enums.ApplicantsSignStatusEnum;
import me.zhengjie.modules.web.service.mybatisplus.ICourseApplicantsPlusService;
import me.zhengjie.modules.web.service.mybatisplus.ICourseClassStudentPlusService;
import me.zhengjie.modules.web.service.mybatisplus.ICourseSigninPlusService;
import me.zhengjie.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author 王宇
* @date 2023-09-20
**/
@Slf4j
@Service
@RequiredArgsConstructor
public class CourseSigninServiceImpl implements CourseSigninService {

    private final CourseSigninRepository courseSigninRepository;
    private final CourseSigninMapper courseSigninMapper;

    @Autowired
    ICourseClassStudentPlusService studentPlusService;

    @Autowired
    ICourseSigninPlusService signinPlusService;

    @Autowired
    CourseInfoService courseInfoService;

    @Autowired
    CourseClassService courseClassService;

    @Autowired
    ExamResultService examResultService;

    @Autowired
    WxUserService wxUserService;

    @Autowired
    private ICourseClassStudentPlusService courseClassStudentPlusService;
    @Autowired
    private ICourseApplicantsPlusService applicantsPlusService;


    @Override
    public Map<String,Object> queryAll(CourseSigninQueryCriteria criteria, Pageable pageable){

        //未签到的直接查询学员表，不分页
        if (Objects.nonNull(criteria.getSigninStatus()) && criteria.getSigninStatus() == ConstantUtils.InValid){
            Map<String, Object> data = new HashMap<String,Object>(){{
                put("content", new ArrayList<>());
                put("totalElements", 0);
            }};
            LambdaQueryWrapper<CourseClassStudent> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(CourseClassStudent::getClassNo,criteria.getClassNo());
            if (StringUtils.isNotBlank(criteria.getGroupNo())){
                wrapper.eq(CourseClassStudent::getGroupNumber,criteria.getGroupNo());
            }
            if(StringUtils.isNotBlank(criteria.getChannelSource())){
                wrapper.eq(CourseClassStudent::getChannelSource,criteria.getChannelSource());
            }
            List<CourseClassStudent> list = studentPlusService.list(wrapper);
            if (CollectionUtils.isEmpty(list)){
                return data;
            }
            String courseNo = list.get(0).getCourseNo();
            CourseInfo courseInfo = courseInfoService.getInfoByNo(courseNo);
            String courseName = "";
            if (Objects.nonNull(courseInfo)){
                courseName = courseInfo.getCourseName();
            }
            CourseClass classByCourseNo = courseClassService.getClassByCourseNo(courseNo);
            String className = "";
            if (Objects.nonNull(classByCourseNo)){
                className = classByCourseNo.getName();
            }
            LambdaQueryWrapper<CourseSignin> wrapper1 = new LambdaQueryWrapper<>();
            wrapper1.eq(CourseSignin::getCourseNo,courseNo);
            List<CourseSignin> signedList = signinPlusService.list(wrapper1);

            List<CourseSigninDto> finalList = new ArrayList<>();
            if (CollectionUtils.isEmpty(signedList)){
                for (CourseClassStudent s : list) {
                    CourseSigninDto dto = new CourseSigninDto();
                    dto.setCourseNo(s.getCourseNo());
                    dto.setCourseName(courseName);
                    dto.setName(s.getUserName());
                    dto.setMobile(s.getPhoneNo());
                    dto.setClassName(className);
                    dto.setClassNo(s.getClassNo());
                    dto.setGroupNo(s.getGroupNumber());
                    dto.setNickName(s.getNickName());
                    finalList.add(dto);
                }
                data.put("content",finalList);
            }else {
                for (CourseClassStudent s : list) {
                    boolean result = signedList.stream().anyMatch(b -> b.getMobile().equals(s.getPhoneNo()));
                    if (!result){
                        CourseSigninDto dto = new CourseSigninDto();
                        dto.setCourseNo(s.getCourseNo());
                        dto.setCourseName(courseName);
                        dto.setName(s.getUserName());
                        dto.setMobile(s.getPhoneNo());
                        dto.setClassName(className);
                        dto.setClassNo(s.getClassNo());
                        dto.setGroupNo(s.getGroupNumber());
                        dto.setNickName(s.getNickName());
                        finalList.add(dto);
                    }
                }
                data.put("content",finalList);
            }
            data.put("totalElements", finalList.size());
            return  data;
        }
        Page<CourseSignin> page = courseSigninRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        Map<String, Object> dataMap = PageUtil.toPage(page.map(courseSigninMapper::toDto));

        if (MapUtil.isEmpty(dataMap) || Objects.isNull(dataMap.get("content"))) {
            return null;
        }

        List<CourseSigninDto> content = (List<CourseSigninDto>) dataMap.get("content");
        for (CourseSigninDto courseSigninDto : content) {
            /*LambdaQueryWrapper<ExamResult> examWrapper = new LambdaQueryWrapper<>();
            examWrapper.eq(ExamResult::getWxId,courseSigninDto.getOpenId());
            examWrapper.eq(ExamResult::getAtmrType,"test_type_07");
            List<ExamResult> list1 = examResultPlusService.list(examWrapper);
            if (CollectionUtils.isEmpty(list1)){
                continue;
            }
            ExamResult examResult = list1.get(0);*/

            WxUser user = wxUserService.findByOpenId(courseSigninDto.getOpenId());
            if (Objects.nonNull(user)){
                courseSigninDto.setNickName(user.getNickname());
            }
            if (StringUtils.isBlank(courseSigninDto.getChannelSource())){
                courseSigninDto.setChannelSource("无");
            }
            ExamResultQueryTestDto examResult = examResultService.querAdultTestInfo(courseSigninDto.getOpenId());
            if (Objects.isNull(examResult)){
                courseSigninDto.setAtmrResultType("无");
                courseSigninDto.setSyTeZhi("无");
                continue;
            }
            String sytz = CharMatcher.anyOf("、").replaceFrom(examResult.getSyTeZhi(), "-");
            courseSigninDto.setAtmrResultType(StringUtils.defaultIfBlank(examResult.getAtmrResultType(),"无"));
            courseSigninDto.setSyTeZhi(StringUtils.defaultIfBlank(sytz,"无"));
        }
        //查询该班级所有签到记录
        LambdaQueryWrapper<CourseSignin> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CourseSignin::getClassNo,criteria.getClassNo());
        List<CourseSignin> list = signinPlusService.list(wrapper);
        List<String> collect = list.stream().map(CourseSignin::getOpenId).collect(Collectors.toList());
        List<ExamResultQueryDto> examResultQueryDtos = examResultService.countUserSyTeZhiCnt(collect);
        Map<String,Object> objMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(examResultQueryDtos)){
            int sum = examResultQueryDtos.stream().mapToInt(ExamResultQueryDto::getCnt).sum();
            objMap.put("testCount",sum);
            examResultQueryDtos.stream();
            Map<String, List<ExamResultQueryDto>> map = examResultQueryDtos.stream().collect(Collectors.groupingBy(ExamResultQueryDto -> CharMatcher.anyOf("、").replaceFrom(ExamResultQueryDto.getSyTeZhi(), "-") + ':' + ExamResultQueryDto.getCnt()+"人"));
            String keys = map.keySet().stream()
                    .map(key -> String.valueOf(key))
                    .collect(Collectors.joining(", "));
            objMap.put("sytz",keys);
        }
        //设置新key用来展示测评人数和首要特质
        dataMap.put("atmrExam",objMap);
        return dataMap;
    }

    @Override
    public List<CourseSigninDto> queryAllForDownload(CourseSigninQueryCriteria criteria) {

        List<CourseSigninDto> courseSigninDtoList = queryAll(criteria);
        if (CollectionUtils.isEmpty(courseSigninDtoList)){
            return Collections.emptyList();
        }
        for (CourseSigninDto courseSigninDto : courseSigninDtoList) {
            ExamResultQueryTestDto examResult = examResultService.querAdultTestInfo(courseSigninDto.getOpenId());
            if (Objects.isNull(examResult)){
                courseSigninDto.setAtmrResultType("无");
                courseSigninDto.setSyTeZhi("无");
                continue;
            }
            String sytz = CharMatcher.anyOf("、").replaceFrom(examResult.getSyTeZhi(), "-");
            courseSigninDto.setAtmrResultType(StringUtils.defaultIfBlank(examResult.getAtmrResultType(),"无"));
            courseSigninDto.setSyTeZhi(StringUtils.defaultIfBlank(sytz,"无"));
        }
        return courseSigninDtoList;
    }

    @Override
    public List<CourseSigninDto> statistics(CourseSigninQueryCriteria criteria) {
        if (StringUtils.isBlank(criteria.getClassNo())){
            return Collections.emptyList();
        }
        LambdaQueryWrapper<CourseClassStudent> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CourseClassStudent::getClassNo,criteria.getClassNo());
        List<CourseClassStudent> list = studentPlusService.list(wrapper);
        if (CollectionUtils.isEmpty(list)){
            return Collections.emptyList();
        }
        CourseInfo courseInfo = courseInfoService.getInfoByNo(list.get(0).getCourseNo());
        String courseName = Objects.isNull(courseInfo) ? "无" : courseInfo.getCourseName();
        List<CourseSigninDto> respList = new ArrayList<>();
        List<CourseSigninDto> finalRespList = respList;
        list.forEach(s -> {
            CourseSigninDto dto = new CourseSigninDto();
            dto.setName(s.getUserName());
            dto.setMobile(s.getPhoneNo());
            dto.setCourseName(courseName);
            dto.setGroupNo(s.getGroupNumber());
            List<CourseSignin> signInList = new ArrayList<>();
            if (StringUtils.isNotBlank(s.getOpenId())){
                LambdaQueryWrapper<CourseSignin> signInWrapper = new LambdaQueryWrapper<>();
                signInWrapper.eq(CourseSignin::getOpenId,s.getOpenId()).eq(CourseSignin::getCourseNo,s.getCourseNo());
                signInList = signinPlusService.list(signInWrapper);
            }
            if (StringUtils.isNotBlank(s.getOpenId())){
                dto.setSigninStatus(1);
                ExamResultQueryTestDto examResult = examResultService.querAdultTestInfo(s.getOpenId());
                if (Objects.isNull(examResult)){
                    dto.setAtmrResultType("无");
                    dto.setSyTeZhi("无");
                }else{
                    String sytz = CharMatcher.anyOf("、").replaceFrom(examResult.getSyTeZhi(), "-");
                    dto.setAtmrResultType(StringUtils.defaultIfBlank(examResult.getAtmrResultType(),"无"));
                    dto.setSyTeZhi(StringUtils.defaultIfBlank(sytz,"无"));
                }
            }else {
                dto.setSigninStatus(0);
                //查询用户表是否存在
                List<WxUser> userList = wxUserService.findByMoblie(s.getPhoneNo());
                if (CollectionUtils.isEmpty(userList)){
                    dto.setAtmrResultType("无");
                    dto.setSyTeZhi("无");
                }else{
                    ExamResultQueryTestDto examResult = examResultService.querAdultTestInfo(userList.get(0).getOpenId());
                    if (Objects.isNull(examResult)){
                        dto.setAtmrResultType("无");
                        dto.setSyTeZhi("无");
                    }else{
                        String sytz = CharMatcher.anyOf("、").replaceFrom(examResult.getSyTeZhi(), "-");
                        dto.setAtmrResultType(StringUtils.defaultIfBlank(examResult.getAtmrResultType(),"无"));
                        dto.setSyTeZhi(StringUtils.defaultIfBlank(sytz,"无"));
                    }
                }
            }
            if (CollectionUtils.isEmpty(signInList)){
                dto.setSigninStatus(0);
            }
            dto.setSigninCount(CollectionUtils.isEmpty(signInList) ? 0 : signInList.size());
            if (CollectionUtils.isNotEmpty(signInList)){
                dto.setSignInDetails(signInList.stream().map(this::signInDetail).collect(Collectors.toList()));
            }else {
                dto.setSignInDetails(Collections.emptyList());
            }
            finalRespList.add(dto);
        });

        if (Objects.nonNull(criteria.getSigninStatus())){
            respList = respList.stream().filter(s -> s.getSigninStatus().equals(criteria.getSigninStatus())).collect(Collectors.toList());
        }
        return respList;
    }

    private CourseSigninDto.SignInDetail signInDetail(CourseSignin signIn) {
        CourseSigninDto.SignInDetail detail = new CourseSigninDto.SignInDetail();
        detail.setCreateTime(signIn.getCreateTime());
        detail.setSignType(signIn.getSignType());
        detail.setReason(signIn.getReason());
        detail.setSigninPic(signIn.getSigninPic());
        return detail;
    }


    @Override
    public List<CourseSigninDto> queryAll(CourseSigninQueryCriteria criteria){
        return courseSigninMapper.toDto(courseSigninRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public CourseSigninDto findById(Long signinId) {
        CourseSignin courseSignin = courseSigninRepository.findById(signinId).orElseGet(CourseSignin::new);
        ValidationUtil.isNull(courseSignin.getSigninId(),"CourseSignin","signinId",signinId);
        return courseSigninMapper.toDto(courseSignin);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CourseSigninDto create(CourseSignin resources) {
        return courseSigninMapper.toDto(courseSigninRepository.save(resources));
    }

    @Override
    public boolean createV2(CourseSignin resources) {

        if (StringUtils.isBlank(resources.getClassNo())){
            throw new BadRequestException("班级编号不能为空");
        }
        if (StringUtils.isBlank(resources.getName())){
            throw new BadRequestException("姓名不能为空");
        }
        if (StringUtils.isBlank(resources.getMobile())){
            throw new BadRequestException("手机号不能为空");
        }
        List<WxUser> userList = wxUserService.findByMoblie(resources.getMobile());
        if (CollectionUtils.isEmpty(userList)){
            throw new BadRequestException("请去个人中心维护信息");
        }

        LambdaQueryWrapper<CourseClassStudent> studentQueryCriteria = new LambdaQueryWrapper<>();
        studentQueryCriteria.eq(CourseClassStudent::getClassNo,resources.getClassNo());
        studentQueryCriteria.eq(CourseClassStudent::getPhoneNo,resources.getMobile());
        List<CourseClassStudent> studentDtoList = courseClassStudentPlusService.list(studentQueryCriteria);
        if (CollectionUtils.isEmpty(studentDtoList)) {
            throw new BadRequestException("课程班级学员信息未维护，请联系工作人员");
        }

        CourseClassStudent courseClassStudent = studentDtoList.get(0);

        String openId = userList.get(0).getOpenId();

        resources.setGroupNo(courseClassStudent.getGroupNumber());
        //更新班级学员表
        CourseClassStudent student = new CourseClassStudent();
        student.setOpenId(openId);
        student.setUpdateTime(DateUtil.TimestampNow());
        LambdaQueryWrapper<CourseClassStudent> modify = new LambdaQueryWrapper<>();
        modify.eq(CourseClassStudent::getStudentId,courseClassStudent.getStudentId());
        courseClassStudentPlusService.update(student,modify);


        resources.setOpenId(openId);
        resources.setCreateTime(DateUtil.TimestampNow());
        resources.setPayMeals(1);
        CourseClass classByCourseNo = courseClassService.getClassByClassNo(resources.getClassNo());

        //更新报名核销
        CourseApplicants applicants = new CourseApplicants();
        applicants.setConsume(ConstantUtils.Valid);
        applicants.setSignStatus(ApplicantsSignStatusEnum.OffLine.getSignStatus());
        LambdaQueryWrapper<CourseApplicants> applicantsWrapper = new LambdaQueryWrapper<>();
        applicantsWrapper.eq(CourseApplicants::getCourseNo,classByCourseNo.getCourseNo());
        applicantsWrapper.eq(CourseApplicants::getMobile,resources.getMobile());
        applicantsPlusService.update(applicants,applicantsWrapper);


        resources.setCourseNo(classByCourseNo.getCourseNo());
        resources.setClassName(classByCourseNo.getName());
        CourseInfo courseInfo = courseInfoService.getInfoByNo(classByCourseNo.getCourseNo());
        resources.setCourseName(courseInfo.getCourseName());
        if (courseSigninRepository.save(resources) != null){
            return true;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(CourseSignin resources) {
        CourseSignin courseSignin = courseSigninRepository.findById(resources.getSigninId()).orElseGet(CourseSignin::new);
        ValidationUtil.isNull( courseSignin.getSigninId(),"CourseSignin","id",resources.getSigninId());
        courseSignin.copy(resources);
        courseSigninRepository.save(courseSignin);
    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long signinId : ids) {
            courseSigninRepository.deleteById(signinId);
        }
    }

    @Override
    public void download(List<CourseSigninDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (CourseSigninDto courseSignin : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("课程名称", courseSignin.getCourseName());
            map.put("班级编号", courseSignin.getClassNo());
            map.put("班级名称", courseSignin.getClassName());
            map.put("姓名", courseSignin.getName());
            map.put("手机号", courseSignin.getMobile());
            map.put("签到时间", courseSignin.getCreateTime());
            map.put("组号", courseSignin.getGroupNo());
            map.put("openid", courseSignin.getOpenId());
            map.put("交餐费", courseSignin.getPayMeals());
            map.put("首要特质", courseSignin.getSyTeZhi());
            map.put("性格类型", courseSignin.getAtmrResultType());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void downloadSignDetail(List<CourseSigninDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (CourseSigninDto courseSignin : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("课程名称", courseSignin.getCourseName());
            map.put("姓名", courseSignin.getName());
            map.put("手机号", courseSignin.getMobile());
            map.put("组号", courseSignin.getGroupNo());
            map.put("是否签到", courseSignin.getSigninCount() > 0 ? "是" : "否");
            map.put("首要特质", courseSignin.getSyTeZhi());
            map.put("性格类型", courseSignin.getAtmrResultType());
            map.put("签到明细", courseSignin.getSignInDetails().stream().map(s -> "签到时间："+s.getCreateTime() + "，签到类型：" + (Integer.valueOf(1).equals(s.getSignType()) ? "手工签到" : "正常签到")  + "，录入原因：" + s.getReason() + "，线下签到图片："+s.getSigninPic()).collect(Collectors.joining("\n")));
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
}